package com.ordertracker.service;

import com.ordertracker.Session;
import com.ordertracker.exception.ValidationException;
import com.ordertracker.protocol.CommandMessage;
import com.ordertracker.to.TransferObjectFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Response;

/**
 * Description of class.
 * Created 2/5/13 3:14 PM
 *
 * @author andrey.rodin@playtech.com
 */

@Service(value = "handleTemplate")
public abstract class AbstractCRUDEventHandle<T> implements HandleChain  {

    protected HandleChain chain;

    protected TransferObjectFactory transferObjectFactory;

    @Resource(name = "defaultMan")
    public void setChain(HandleChain chain) {
        this.chain = chain;
    }

    @Resource(name = "tof")
    public void setTransferObjectFactory(TransferObjectFactory transferObjectFactory) {
        this.transferObjectFactory = transferObjectFactory;
    }

    @SuppressWarnings("unchecked")
    public final Response handleMessage(Session session, CommandMessage msg, ActionType type) throws WebApplicationException {
        if (! msg.getType().toLowerCase().contains(getServiceName())) {
            chain.handleMessage(session, msg, type);
        }
        T obj = null;

        if (needToUnmarshal(type)) {
            try {
                obj = (T) unmarshal(msg.getObj());
                validate(session, obj, type);
            } catch (Exception ex) {
                throw new WebApplicationException(ex);
            }
        }

        switch (type) {
            case ADD:
                return Response.ok(create(session, obj)).build();
            case GET:
                return Response.ok(receive(msg)).build();
            case UPDATE:
               return Response.ok(update(session, obj)).build();
            case DELETE:
                return Response.ok(delete(session, obj)).build();
            default:
                return otherAction(session, msg, obj, type);
        }
    }


    protected abstract Object unmarshal(String obj) throws Exception;
    protected abstract String getServiceName();
    protected abstract void validate(Session session, T msg, ActionType type) throws ValidationException;
    protected abstract Response otherAction(Session session, CommandMessage msg, T obj, ActionType type);
    protected abstract boolean needToUnmarshal(ActionType type);

    @Transactional
    protected abstract Object create(Session session, T obj);

    @Transactional(readOnly = true)
    protected abstract Object receive(CommandMessage msg);

    @Transactional
    protected abstract Object delete(Session session, T obj);

    @Transactional
    protected abstract Object update(Session session, T obj);
}
